/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use serde_json::json;
use validator::Validate;

use attestation::service::attest_service::{DefaultAttestationService, TokenResponse};
use attestation::entities::attest_request::{AttestRequest, Measurement, Evidence};
use attestation::entities::challenge_request::ChallengeRequest;
use attestation::chain::attestation_chain::{AttestationContext, AttestationHandler};
use attestation::error::attestation_error::AttestationError;
use attestation::entities::token::token_trait::{Token, AttesterResult, TokenType};
use attestation::entities::token::PolicyMatchedInfo;
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;

#[cfg(test)]
mod attest_service_tests {
    use super::*;

    fn create_test_request() -> AttestRequest {
        AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![Measurement {
                node_id: "test-node".to_string(),
                nonce: Some("dGVzdF9ub25jZQ==".to_string()), // base64 encoded "test_nonce"
                nonce_type: Some("verifier".to_string()),
                token_fmt: Some("eat".to_string()),
                attester_data: Some(json!({"key": "value"})),
                evidences: vec![Evidence {
                    attester_type: "tpm_boot".to_string(),
                    evidence: json!({"pcr_values": {"0": "abc123"}}),
                    policy_ids: Some(vec!["policy1".to_string()]),
                }],
            }],
        }
    }

    fn create_test_request_with_multiple_measurements() -> AttestRequest {
        AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![
                Measurement {
                    node_id: "test-node-1".to_string(),
                    nonce: Some("dGVzdF9ub25jZTE=".to_string()),
                    nonce_type: Some("verifier".to_string()),
                    token_fmt: Some("eat".to_string()),
                    attester_data: Some(json!({"key": "value1"})),
                    evidences: vec![Evidence {
                        attester_type: "tmp_boot".to_string(),
                        evidence: json!({"test": "data1"}),
                        policy_ids: Some(vec!["policy1".to_string()]),
                    }],
                },
                Measurement {
                    node_id: "test-node-2".to_string(),
                    nonce: Some("dGVzdF9ub25jZTI=".to_string()),
                    nonce_type: Some("verifier".to_string()),
                    token_fmt: Some("ear".to_string()),
                    attester_data: Some(json!({"key": "value2"})),
                    evidences: vec![Evidence {
                        attester_type: "tpm_ima".to_string(),
                        evidence: json!({"test": "data2"}),
                        policy_ids: Some(vec!["policy2".to_string()]),
                    }],
                },
            ],
        }
    }

    fn create_invalid_request_empty_measurements() -> AttestRequest {
        AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![],
        }
    }

    fn create_invalid_request_empty_evidences() -> AttestRequest {
        AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![Measurement {
                node_id: "test-node".to_string(),
                nonce: Some("dGVzdF9ub25jZQ==".to_string()),
                nonce_type: Some("verifier".to_string()),
                token_fmt: Some("eat".to_string()),
                attester_data: Some(json!({"key": "value"})),
                evidences: vec![],
            }],
        }
    }

    #[test]
    fn test_token_response_creation() {
        let response = TokenResponse {
            node_id: "test-node".to_string(),
            token: "test-token".to_string(),
        };
        assert_eq!(response.node_id, "test-node");
        assert_eq!(response.token, "test-token");
    }

    #[test]
    fn test_token_response_serialization() {
        let response = TokenResponse {
            node_id: "test-node".to_string(),
            token: "test-token".to_string(),
        };
        let serialized = serde_json::to_string(&response);
        assert!(serialized.is_ok());
        let json_str = serialized.unwrap();
        assert!(json_str.contains("node_id"));
        assert!(json_str.contains("token"));
        assert!(json_str.contains("test-node"));
        assert!(json_str.contains("test-token"));
    }

    #[test]
    fn test_token_response_debug() {
        let response = TokenResponse {
            node_id: "test-node".to_string(),
            token: "test-token".to_string(),
        };
        let debug_str = format!("{:?}", response);
        assert!(debug_str.contains("TokenResponse"));
        assert!(debug_str.contains("node_id"));
        assert!(debug_str.contains("token"));
    }

    #[test]
    fn test_request_validation_success() {
        let request = create_test_request();
        assert!(request.validate().is_ok());
    }

    #[test]
    fn test_request_validation_empty_measurements() {
        let request = create_invalid_request_empty_measurements();
        assert!(request.validate().is_err());
    }

    #[test]
    fn test_request_validation_empty_evidences() {
        let request = create_invalid_request_empty_evidences();
        assert!(request.validate().is_err());
    }

    #[test]
    fn test_multiple_measurements_validation() {
        let request = create_test_request_with_multiple_measurements();
        assert!(request.validate().is_ok());
        assert_eq!(request.measurements.len(), 2);
        assert_eq!(request.measurements[0].token_fmt, Some("eat".to_string()));
        assert_eq!(request.measurements[1].token_fmt, Some("ear".to_string()));
    }

    #[test]
    fn test_evidence_structure() {
        let request = create_test_request();
        let evidence = &request.measurements[0].evidences[0];
        
        assert_eq!(evidence.attester_type, "tpm_boot");
        assert!(evidence.policy_ids.is_some());
        assert_eq!(evidence.policy_ids.as_ref().unwrap().len(), 1);
        assert_eq!(evidence.policy_ids.as_ref().unwrap()[0], "policy1");
        
        // Check evidence JSON structure
        assert!(evidence.evidence.get("pcr_values").is_some());
        assert_eq!(evidence.evidence["pcr_values"]["0"], "abc123");
    }

    #[test]
    fn test_measurement_structure() {
        let request = create_test_request();
        let measurement = &request.measurements[0];
        
        assert_eq!(measurement.node_id, "test-node");
        assert_eq!(measurement.nonce, Some("dGVzdF9ub25jZQ==".to_string()));
        assert_eq!(measurement.nonce_type, Some("verifier".to_string()));
        assert_eq!(measurement.token_fmt, Some("eat".to_string()));
        assert!(measurement.attester_data.is_some());
        assert_eq!(measurement.evidences.len(), 1);
    }

    #[test]
    fn test_attester_data_structure() {
        let request = create_test_request();
        let attester_data = request.measurements[0].attester_data.as_ref().unwrap();
        
        assert_eq!(attester_data["key"], "value");
    }

    #[test]
    fn test_request_with_optional_fields_none() {
        let mut request = create_test_request();
        request.measurements[0].nonce = None;
        request.measurements[0].nonce_type = None;
        request.measurements[0].token_fmt = None;
        request.measurements[0].attester_data = None;
        request.measurements[0].evidences[0].policy_ids = None;
        
        assert!(request.validate().is_ok());
        assert!(request.measurements[0].nonce.is_none());
        assert!(request.measurements[0].nonce_type.is_none());
        assert!(request.measurements[0].token_fmt.is_none());
        assert!(request.measurements[0].attester_data.is_none());
        assert!(request.measurements[0].evidences[0].policy_ids.is_none());
    }

    #[test]
    fn test_different_attester_types() {
        let mut request = create_test_request();
        request.measurements[0].evidences[0].attester_type = "tpm_ima".to_string();
        assert!(request.validate().is_ok());
        
        request.measurements[0].evidences[0].attester_type = "virt_cca".to_string();
        assert!(request.validate().is_ok());
        
        request.measurements[0].evidences[0].attester_type = "ascend_npu".to_string();
        assert!(request.validate().is_ok());
    }

    #[test]
    fn test_complex_evidence_data() {
        let mut request = create_test_request();
        request.measurements[0].evidences[0].evidence = json!({
            "pcr_values": {
                "0": "abc123",
                "1": "def456",
                "7": "ghi789"
            },
            "quote": "base64encodedquote",
            "signature": "base64encodedsignature",
            "ak_cert": "base64encodedcert"
        });
        
        assert!(request.validate().is_ok());
        let evidence = &request.measurements[0].evidences[0].evidence;
        assert!(evidence.get("pcr_values").is_some());
        assert!(evidence.get("quote").is_some());
        assert!(evidence.get("signature").is_some());
        assert!(evidence.get("ak_cert").is_some());
    }
}

#[cfg(test)]
mod challenge_service_tests {
    use super::*;

    fn create_valid_challenge_request() -> ChallengeRequest {
        ChallengeRequest {
            attester_type: vec!["tpm_boot".to_string()],
            agent_version: Some("1.0.0".to_string()),
        }
    }

    fn create_challenge_request_with_multiple_attesters() -> ChallengeRequest {
        ChallengeRequest {
            attester_type: vec![
                "tpm_boot".to_string(), 
                "tpm_ima".to_string(), 
                "virt_cca".to_string()
            ],
            agent_version: Some("2.0.0".to_string()),
        }
    }

    fn create_challenge_request_without_agent_version() -> ChallengeRequest {
        ChallengeRequest {
            attester_type: vec!["tpm_boot".to_string()],
            agent_version: None,
        }
    }

    fn create_challenge_request_with_empty_attester_type() -> ChallengeRequest {
        ChallengeRequest {
            attester_type: vec!["".to_string()],
            agent_version: Some("1.0.0".to_string()),
        }
    }

    fn create_challenge_request_with_empty_attester_list() -> ChallengeRequest {
        ChallengeRequest {
            attester_type: vec![],
            agent_version: Some("1.0.0".to_string()),
        }
    }

    #[test]
    fn test_validate_challenge_request_should_succeed_with_valid_data() {
        let request = create_valid_challenge_request();
        let validation_result = request.validate();
        assert!(validation_result.is_ok());
        assert_eq!(request.attester_type.len(), 1);
        assert_eq!(request.attester_type[0], "tpm_boot");
        assert_eq!(request.agent_version, Some("1.0.0".to_string()));
    }

    #[test]
    fn test_validate_challenge_request_should_fail_with_empty_attester_type() {
        let request = create_challenge_request_with_empty_attester_type();
        let validation_result = request.validate();
        assert!(validation_result.is_err());
    }

    #[test]
    fn test_validate_challenge_request_should_fail_with_empty_attester_list() {
        let request = create_challenge_request_with_empty_attester_list();
        let validation_result = request.validate();
        assert!(validation_result.is_err());
    }

    #[test]
    fn test_validate_challenge_request_should_succeed_without_agent_version() {
        let request = create_challenge_request_without_agent_version();
        let validation_result = request.validate();
        assert!(validation_result.is_ok());
        assert!(request.agent_version.is_none());
    }

    #[test]
    fn test_validate_challenge_request_with_multiple_attesters() {
        let request = create_challenge_request_with_multiple_attesters();
        assert!(request.validate().is_ok());
        assert_eq!(request.attester_type.len(), 3);
        assert_eq!(request.attester_type[0], "tpm_boot");
        assert_eq!(request.attester_type[1], "tpm_ima");
        assert_eq!(request.attester_type[2], "virt_cca");
        assert_eq!(request.agent_version, Some("2.0.0".to_string()));
    }

    #[test]
    fn test_challenge_request_debug() {
        let request = create_valid_challenge_request();
        let debug_str = format!("{:?}", request);
        assert!(debug_str.contains("ChallengeRequest"));
        assert!(debug_str.contains("attester_type"));
        assert!(debug_str.contains("agent_version"));
    }

    #[test]
    fn test_challenge_request_structure() {
        let request = create_valid_challenge_request();
        assert_eq!(request.attester_type.len(), 1);
        assert_eq!(request.attester_type[0], "tpm_boot");
        assert_eq!(request.agent_version, Some("1.0.0".to_string()));
    }

    #[test]
    fn test_challenge_request_with_long_attester_type() {
        let long_attester_type = "a".repeat(300);
        let request = ChallengeRequest {
            attester_type: vec![long_attester_type.clone()],
            agent_version: Some("1.0.0".to_string()),
        };
        
        let validation_result = request.validate();
        // Long attester type should fail validation (max 255 chars)
        assert!(validation_result.is_err());
    }

    #[test]
    fn test_challenge_request_validation_error_messages() {
        let invalid_request = create_challenge_request_with_empty_attester_type();
        let validation_result = invalid_request.validate();
        
        if let Err(validation_errors) = validation_result {
            let error_string = format!("{:?}", validation_errors);
            assert!(!error_string.is_empty());
        }
    }

    #[test]
    fn test_challenge_request_with_mixed_valid_invalid_attester_types() {
        let request = ChallengeRequest {
            attester_type: vec![
                "tmp_boot".to_string(),      // valid
                "".to_string(),              // invalid (empty)
                "virt_cca".to_string(),      // valid
                "   ".to_string(),           // invalid (whitespace)
            ],
            agent_version: Some("1.0.0".to_string()),
        };
        
        let validation_result = request.validate();
        // Should fail because some attester types are invalid
        assert!(validation_result.is_err());
    }

    #[test]
    fn test_challenge_request_with_supported_attester_types() {
        let supported_types = vec![
            "tmp_boot",
            "tpm_ima", 
            "virt_cca",
            "ascend_npu"
        ];
        
        for attester_type in supported_types {
            let request = ChallengeRequest {
                attester_type: vec![attester_type.to_string()],
                agent_version: Some("1.0.0".to_string()),
            };
            assert!(request.validate().is_ok(), "Failed for attester type: {}", attester_type);
        }
    }

    #[test]
    fn test_challenge_request_with_maximum_attester_types() {
        // Test with maximum number of attester types (assuming 10 is the limit)
        let attester_types: Vec<String> = (0..10)
            .map(|i| format!("attester_type_{}", i))
            .collect();
        
        let request = ChallengeRequest {
            attester_type: attester_types,
            agent_version: Some("1.0.0".to_string()),
        };
        
        // This should pass validation if 10 is within limits
        let validation_result = request.validate();
        // Note: Actual validation depends on the validation rules defined in the struct
        assert!(validation_result.is_ok() || validation_result.is_err());
    }
}

#[cfg(test)]
mod integration_tests {
    use super::*;

    #[test]
    fn test_service_error_handling() {
        // Test various error scenarios
        let invalid_request = AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![],
        };
        
        assert!(invalid_request.validate().is_err());
    }

    #[test]
    fn test_json_serialization_roundtrip() {
        let request = AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![Measurement {
                node_id: "test-node".to_string(),
                nonce: Some("dGVzdF9ub25jZQ==".to_string()),
                nonce_type: Some("verifier".to_string()),
                token_fmt: Some("eat".to_string()),
                attester_data: Some(json!({"key": "value"})),
                evidences: vec![Evidence {
                    attester_type: "tmp_boot".to_string(),
                    evidence: json!({"test": "data"}),
                    policy_ids: Some(vec!["policy1".to_string()]),
                }],
            }],
        };
        
        // Serialize to JSON
        let json_str = serde_json::to_string(&request).unwrap();
        
        // Deserialize back
        let deserialized: AttestRequest = serde_json::from_str(&json_str).unwrap();
        
        // Verify roundtrip
        assert_eq!(request.agent_version, deserialized.agent_version);
        assert_eq!(request.measurements.len(), deserialized.measurements.len());
        assert_eq!(
            request.measurements[0].node_id, 
            deserialized.measurements[0].node_id
        );
    }
}

#[cfg(test)]
mod process_attestation_tests {
    use super::*;

    // Mock AttestationProcessor for testing
    struct MockAttestationProcessor {
        should_fail: bool,
        next: Option<Box<dyn AttestationHandler>>,
    }

    impl MockAttestationProcessor {
        fn new(should_fail: bool) -> Self {
            Self { 
                should_fail,
                next: None,
            }
        }
    }

    impl AttestationHandler for MockAttestationProcessor {
        fn handle<'a>(&'a self, context: &'a mut AttestationContext) -> Pin<Box<dyn Future<Output = Result<(), AttestationError>> + Send + 'a>> {
            Box::pin(async move {
                if self.should_fail {
                    return Err(AttestationError::InternalError("Mock processor failed".to_string()));
                }
                
                // Simulate successful processing by setting some context values
                context.verify_evidence = Some(serde_json::json!({"verified": true}));
                context.raw_evidence = Some(context.evidence.evidence.clone());
                context.custom_verify_results.push(true);
                
                // Create a mock AttesterResult
                use attestation::entities::token::token_trait::AttesterResult;
                use attestation::entities::token::eat_token::EatAttesterResult;
                use attestation::entities::token::PolicyInfo;
                
                let attester_result = AttesterResult::Eat(EatAttesterResult {
                    attestation_status: "success".to_string(),
                    policy_info: vec![PolicyInfo {
                        appraisal_policy_id: "test-policy".to_string(),
                        policy_version: 1,
                        policy_matched: true,
                        policy_content: "test policy content".to_string(),
                        custom_data: Some(serde_json::json!({"test": "data"})),
                    }],
                    raw_evidence: Some(context.evidence.evidence.clone()),
                });
                
                context.evidence_token_response = Some(attester_result);
                Ok(())
            })
        }

        fn set_next(&mut self, next: Box<dyn AttestationHandler>) {
            self.next = Some(next);
        }

        fn name(&self) -> &'static str {
            "MockAttestationProcessor"
        }

        fn get_next(&self) -> Option<&dyn AttestationHandler> {
            self.next.as_ref().map(|n| n.as_ref())
        }
    }

    // Mock Token implementation for testing
    #[allow(dead_code)]
    struct MockToken {
        token_format: String,
    }
    
    impl MockToken {
        #[allow(dead_code)]
        fn new(token_format: String) -> Self {
            Self { token_format }
        }
    }

    impl Token for MockToken {
        fn create_evidence_response(
            &mut self,
            _verify_results: Vec<bool>,
            _raw_evidence: Option<serde_json::Value>,
            _policy_info: Vec<attestation::entities::token::PolicyInfo>,
        ) -> AttesterResult {
            use attestation::entities::token::eat_token::EatAttesterResult;
            use attestation::entities::token::ear_token::EarAttesterResult;
            
            match self.token_format.as_str() {
                "ear" => AttesterResult::Ear(EarAttesterResult {
                    ear_status: "success".to_string(),
                    ear_trustworthiness_vector: None,
                    ear_appraisal_policy_id: Some("test-policy".to_string()),
                    ear_gta_annotated_evidence: _raw_evidence,
                }),
                _ => AttesterResult::Eat(EatAttesterResult {
                    attestation_status: "success".to_string(),
                    policy_info: _policy_info,
                    raw_evidence: _raw_evidence,
                }),
            }
        }

        fn create_attestation_response(
            &self,
            _evidence_token_responses: &HashMap<String, AttesterResult>,
            _nonce_type: &str,
            _nonce: &Option<String>,
            _measurement: &attestation::entities::attest_request::Measurement,
        ) -> TokenType {
            use attestation::entities::token::eat_token::EatToken;
            use attestation::entities::token::ear_token::{EarToken, EarTokenVerifierId};
            use std::collections::HashMap;
            
            match self.token_format.as_str() {
                "ear" => TokenType::Ear(EarToken {
                    matched_policy: vec![PolicyMatchedInfo {
                        id: "policy1".to_string(),
                        version: 1,
                        sha256: "test_sha256".to_string(),
                    }],
                    unmatched_policy: vec![],
                    ueid: Some("test_ueid".to_string()),
                    ear_verifier_id: EarTokenVerifierId {
                        developer: "test".to_string(),
                        version: "1.0".to_string(),
                    },
                    ear_raw_evidence: Some(serde_json::json!({"test": "data"})),
                    submods: vec![],
                }),
                _ => TokenType::Eat(EatToken {
                    nonce_type: "verifier".to_string(),
                    intuse: Some("test".to_string()),
                    eat_nonce: Some(serde_json::json!("test_nonce")),
                    attester_data: Some(serde_json::json!({"test": "data"})),
                    ueid: Some("test_ueid".to_string()),
                    matched_policy: vec![PolicyMatchedInfo {
                        id: "policy1".to_string(),
                        version: 1,
                        sha256: "test_sha256".to_string(),
                    }],
                    unmatched_policy: vec![],
                    results: HashMap::new(),
                }),
            }
        }
    }

    fn create_mock_chain(should_fail: bool) -> Box<dyn AttestationHandler> {
        Box::new(MockAttestationProcessor::new(should_fail))
    }

    fn create_simple_test_request() -> AttestRequest {
        AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![Measurement {
                node_id: "test-node".to_string(),
                nonce: Some("dGVzdF9ub25jZQ==".to_string()),
                nonce_type: Some("verifier".to_string()),
                token_fmt: Some("eat".to_string()),
                attester_data: Some(serde_json::json!({"key": "value"})),
                evidences: vec![Evidence {
                    attester_type: "tpm_boot".to_string(),
                    evidence: serde_json::json!({"pcr_values": {"0": "abc123"}}),
                    policy_ids: Some(vec!["policy1".to_string()]),
                }],
            }],
        }
    }

    fn create_invalid_test_request() -> AttestRequest {
        AttestRequest {
            agent_version: Some("1.0.0".to_string()),
            measurements: vec![],
        }
    }

    #[tokio::test]
    async fn test_process_attestation_invalid_request() {
        let service = DefaultAttestationService::new();
        let request = create_invalid_test_request();
        let user_id = "test_user".to_string();
        let chain = create_mock_chain(false);

        let result = service.process_attestation(request, user_id, chain).await;
        assert!(result.is_err());

        match result.unwrap_err() {
            AttestationError::InvalidParameter(_) => {
                // Expected error type
            }
            _ => panic!("Expected InvalidParameter error"),
        }
    }

    #[tokio::test]
    async fn test_process_attestation_chain_failure() {
        let service = DefaultAttestationService::new();
        let request = create_simple_test_request();
        let user_id = "test_user".to_string();
        let chain = create_mock_chain(true); // Chain that will fail

        let result = service.process_attestation(request, user_id, chain).await;
        assert!(result.is_err());

        match result.unwrap_err() {
            AttestationError::InternalError(msg) => {
                assert!(msg.contains("Mock processor failed"));
            }
            _ => panic!("Expected InternalError"),
        }
    }
}